package cn.edu.dgut.css.sai.dgutoauth2.oauth;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>自定义{@link OAuth2AccessTokenResponseClient} 用于获取access_token</p>
 * <p>莞工CAS-参考文档，查看密码cas ：http://doc.dgut.edu.cn/web/#/4?page_id=22</p>
 *
 * @author sai
 * @since 1.0
 */
final class SaiDGUTOAuth2AccessTokenResponseClient implements OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {

    final String CHECK_TOKEN_API = "https://cas.dgut.edu.cn/ssoapi/v2/checkToken";
    private final RestTemplate restTemplate;

    public SaiDGUTOAuth2AccessTokenResponseClient(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    @Override
    public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationGrantRequest) {
        // @formatter:off
        // 构造请求正文,POST请求.
        UriComponents uriComponents = UriComponentsBuilder.fromUriString(CHECK_TOKEN_API).build();
        MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
        queryParams.add("token",authorizationGrantRequest.getAuthorizationExchange().getAuthorizationResponse().getCode());
        queryParams.add("appid", authorizationGrantRequest.getClientRegistration().getClientId());
        queryParams.add("appsecret", authorizationGrantRequest.getClientRegistration().getClientSecret());
        queryParams.add("userip","127.0.0.1");
        RequestEntity<MultiValueMap<String,String>> accessTokenRequestEntity = RequestEntity.post(uriComponents.toUri()).body(queryParams);
        // 请求access_token.
        ResponseEntity<Map<String, Object>> accessTokenResponseEntity = restTemplate.exchange(accessTokenRequestEntity, new ParameterizedTypeReference<>() {});
        // @formatter:on

        // 转换为 OAuth2AccessTokenResponse
        Map<String, Object> accessTokenResponseBody = accessTokenResponseEntity.getBody();
        Assert.notNull(accessTokenResponseBody, "accessTokenResponseBody 不能为 null");
        Assert.isTrue("0".equals(String.valueOf(accessTokenResponseBody.get("error"))), "token验证失败!");

        return OAuth2AccessTokenResponse
                .withToken((String) accessTokenResponseBody.get("access_token"))
                .tokenType(OAuth2AccessToken.TokenType.BEARER) // Spring Security OAuth2 内部不允许 TokenType 为 空。
                .expiresIn(TimeUnit.MINUTES.toMillis(5)) // access_token只能用一次，5分钟内有效。
                .scopes(Collections.singleton("DGUT")) // 自定义一个。
                .additionalParameters(accessTokenResponseBody)
                .build();
    }
}
